package com.winchain.chainbill.bill.biz.contract.service.impl;

import com.shell.bee.base.exception.UnCheckException;
import com.shell.bee.base.exception.UnCheckMsgException;
import com.shell.bee.base.service.BaseService;
import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.base.utils.JsonUtil;
import com.shell.bee.base.utils.RandomUtil;
import com.shell.bee.base.utils.SpringContextUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.base.utils.SystemUtil.SystemMode;
import com.shell.bee.cfca.CfcaConfiguration;
import com.shell.bee.cfca.base.po.CfcaSmsLog;
import com.shell.bee.cfca.base.service.CfcaSmsLogService;
import com.shell.bee.entity.auth.AuthOrgan;
import com.shell.bee.entity.auth.AuthUser;
import com.shell.bee.entity.mvc.RetMsg;
import com.shell.bee.esign.po.EsCust;
import com.shell.bee.esign.service.EsCustService;
import com.shell.bee.esign.service.EsignSignService;
import com.shell.contract.po.ConErrRec;
import com.shell.contract.po.Contract;
import com.shell.contract.vo.ContractResponseBodyVo;
import com.shell.feign.ConErrRecFeign;
import com.shell.feign.ContractApiFeign;
import com.shell.feign.ContractFeign;
import com.shell.feign.PubMessageFeign;
import com.shell.feign.PubOrganFeign;
import com.shell.feign.PubUserFeign;
import com.shell.framework.utils.CommonDataUtil;
import com.shell.governor.modules.message.keyword.PaperlessSignKeyWord;
import com.shell.governor.organization.po.PubOrgan;
import com.shell.governor.user.po.PubUser;
import com.shell.sms.SMSResponse;
import com.timevale.esign.sdk.tech.bean.result.Result;
import com.winchain.chainbill.basic.cus.po.CusRec;
import com.winchain.chainbill.basic.cus.service.CusRecService;
import com.winchain.chainbill.bill.base.po.CbDct;
import com.winchain.chainbill.bill.base.po.CbXfe;
import com.winchain.chainbill.bill.base.service.CbDctService;
import com.winchain.chainbill.bill.base.service.CbXfeService;
import com.winchain.chainbill.bill.biz.contract.service.ContractBizService;
import com.winchain.chainbill.bill.biz.contract.vo.ContractRetVo;
import com.winchain.chainbill.bill.biz.discount.service.BillDctRevService;
import com.winchain.chainbill.bill.biz.receive.service.BillRcvService;
import com.winchain.chainbill.bill.biz.send.service.BillSndRevService;
import com.winchain.chainbill.bill.biz.send.vo.BatchBillStats;
import com.winchain.chainbill.bill.biz.transfer.service.BillXfeRevService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service("contractBizService")
public class ContractBizServiceImpl extends BaseService implements ContractBizService {
	@Autowired
	private ContractFeign contractFeign;
	@Autowired
	private ContractApiFeign contractApiFeign;
	@Autowired
	private BillSndRevService billSndRevService;
	@Autowired
	private BillRcvService billRcvService;
	@Autowired
	private BillXfeRevService billXfeRevService;
	@Autowired
	private BillDctRevService billDctRevService;
	@Autowired
	private ConErrRecFeign conErrRecFeign;
	@Autowired
	private CbDctService cbDctService;
	@Autowired
	private CbXfeService cbXfeService;
	@Autowired
	private CusRecService cusRecService;
	@Autowired
	private PubUserFeign pubUserFeign;
	@Autowired
	private PubOrganFeign pubOrganFeign;
	@Autowired
	private EsCustService esCustService;
	@Autowired
	private EsignSignService esignSignService;
	@Autowired
	private PubMessageFeign pubMessageFeign;
	@Value("${sms.gateway: ''}")
	private String smsGateway;
	@Autowired
	private CfcaSmsLogService cfcaSmsLogService;
	private static final String CHECK_SIGNED_STR_1 = "����������";
	private static final String CHECK_SIGNED_STR_2 = "��������������������";
	private static final String CUS_ID = "cus_id";
	private static final String CONTRACT_IDS = "contract_ids";
	private static final String ACCEPTOR_ID = "acceptor_id";
	private static final String NOTARYID = "notaryid";
	private static final String BIZ_TYPE = "biz_type";
	private static final String FILE_IDS = "file_ids";
	private static final String CONTRACTS = "contracts";
	private static final String INVOICES = "invoices";
	private static final String SIGNED_BILL_IDS = "signed_bill_ids";
	private static final String DOC_ID = "docid";
	private static final String DOC_FINISHED = "docfinished";
	private static Set<String> respKeySet = new HashSet();

	static {
		respKeySet.add("errorCode");
		respKeySet.add("cus_id");
		respKeySet.add("contract_ids");
		respKeySet.add("acceptor_id");

		respKeySet.add("biz_type");
	}

	public ContractRetVo signContracts(String bizType, String fileIds, String contracts, String invoices,
			String billIds) {
		ContractRetVo ret = new ContractRetVo();

		String[] billIdArr = billIds.split(",");
		if ("off".equals(SpringContextUtil.getProperty("contract.switch"))) {
			processSignedSuccess(ret, new HashSet(Arrays.asList(billIdArr)), bizType, fileIds, contracts, invoices);
			ret.setSigned(true);
			return ret;
		}
		String cusId = CommonDataUtil.getCurEntId();
		String userId = CommonDataUtil.getUserId();
		Set<String> signedBills = new HashSet();
		List<String> unsignBills = new ArrayList();
		for (String billId : billIdArr) {
			List<String> unsignBillIds = getSignBillId(billId, bizType);
			String signBillId = (String) unsignBillIds.get(0);
			boolean isSigned = checkIsSigned(signBillId, cusId, userId, bizType);
			if (isSigned) {
				signedBills.add(billId);
			} else {
				unsignBills.addAll(unsignBillIds);
			}
		}
		if (signedBills.size() == billIdArr.length) {
			processSignedSuccess(ret, signedBills, bizType, fileIds, contracts, invoices);
		} else {
			try {
				String signedBillsJson = "";
				if (signedBills.size() > 0) {
					signedBillsJson = JsonUtil.toJson(signedBills);
				}
				String unsignBillsJson = JsonUtil.toJson(unsignBills);
				String paramStr = getSignContractInfos(signedBillsJson, unsignBillsJson, fileIds, contracts, invoices);
				if (StringUtil.emptyAndNull(paramStr)) {
					throw new UnCheckException("����������������");
				}
				Map<String, String> param = (Map) JsonUtil.fromJson(paramStr, Map.class);
				ret.setParam(param);
			} catch (Exception e) {
				throw new UnCheckException("json��������: " + e.getMessage());
			}
		}
		return ret;
	}

	private boolean checkIsSigned(String signBillId, String cusId, String userId, String bizType) {
		boolean isSigned = false;
		Contract contract = this.contractFeign.selectLatestByBillIdAndCusId(signBillId, cusId);
		String contractState = contract.getContractState();
		if ((("3".equals(contractState)) && (cusId.equals(contract.getSponsorId())))
				|| (("6".equals(contractState)) && (cusId.equals(contract.getAcceptorId())))) {
			isSigned = true;
		} else if (("2".equals(contractState)) || ("5".equals(contractState))) {
			ContractResponseBodyVo resp = this.contractApiFeign.accept(cusId, userId, signBillId);
			if (resp.isSuccess()) {
				String respHtml = resp.getRespHtml();
				if ((respHtml.contains("����������")) || (respHtml.contains("��������������������"))) {
					isSigned = true;
					if ("13".equals(bizType)) {
						contractState = "6";
						List<ConErrRec> errRecs = this.conErrRecFeign.selectList(contract.getContractId(), "0");
						if (errRecs.size() > 0) {
							contract.setNotaryId(((ConErrRec) errRecs.get(0)).getNotaryId());
						}
					} else {
						contractState = "3";
					}
				} else if ("13".equals(bizType)) {
					contractState = "7";
				} else {
					contractState = "4";
				}
				contract.setContractState(contractState);
				this.contractFeign.update(contract);
			}
		}
		return isSigned;
	}

	private String getSignContractInfos(String signedBillsJson, String unsignBillsJson, String fileIds,
			String contracts, String invoices) {
		String cusId = CommonDataUtil.getCurEntId();
		String userId = CommonDataUtil.getUserId();
		return this.contractApiFeign.genBatchAcceptParamStr(cusId, userId, signedBillsJson, unsignBillsJson, fileIds,
				contracts, invoices);
	}

	private List<String> getSignBillId(String billId, String bizType) {
		List<String> signBillIds = new ArrayList();

		boolean currentBill = true;
		if ("11".equals(bizType)) {
			CbXfe tmp = new CbXfe();
			tmp.setPrntId(billId);
			tmp.setXfeState("1");
			List<CbXfe> xfes = this.cbXfeService.selectByEntity(tmp);
			if (xfes.size() > 0) {
				currentBill = false;
				for (CbXfe xfe : xfes) {
					signBillIds.add(xfe.getBillId());
				}
			}
		} else if ("12".equals(bizType)) {
			CbDct tmp = new CbDct();
			tmp.setPrntId(billId);
			tmp.setDctState("1");
			CbDct dct = (CbDct) this.cbDctService.selectOne(tmp);
			if (dct != null) {
				signBillIds.add(dct.getBillId());
				currentBill = false;
			}
		}
		if (currentBill) {
			signBillIds.add(billId);
		}
		return signBillIds;
	}

	private void processSignedSuccess(ContractRetVo ret, Set<String> billIds, String bizType, String fileIds,
			String contracts, String invoices) {
		BatchBillStats<?> stats = bizOperation(billIds, bizType, fileIds, contracts, invoices);
		ret.setBatchBillStats(stats);
		ret.setSigned(true);
	}

	public String getSignContractInfo(String billId, String fileIds, String contracts, String invoices) {
		String cusId = CommonDataUtil.getCurEntId();
		String userId = CommonDataUtil.getUserId();
		return this.contractApiFeign.genAcceptParamStr(cusId, userId, billId, fileIds, contracts, invoices);
	}

	public void handleNotice(String key, String content, String signed) {
		String result = null;
		Map<String, String> resultMap = null;
		ConErrRec errRec = new ConErrRec();
		try {
			try {
				result = getDecryptResult(key, content, signed);
			} catch (Exception e) {
				throw new UnCheckException("����������������", e);
			}
			try {
				resultMap = (Map) JsonUtil.fromJson(result, Map.class);
				checkResponse(resultMap);
			} catch (Exception e) {
				throw new UnCheckException("����������������", e);
			}
			String contractIdsStr = (String) resultMap.get("contract_ids");
			String[] contractIds = contractIdsStr.split(",");
			for (String contractId : contractIds) {
				Contract contract = this.contractFeign.lockByKey(contractId);
				if (contract == null) {
					setErrorRec(errRec, resultMap);
					throw new UnCheckException("������contract_id��" + contractId + "������");
				}
				String contractState = contract.getContractState();
				if ((!"2".equals(contractState)) && (!"5".equals(contractState))) {
					this.logger.error("��������������");
					return;
				}
				String errorCode = (String) resultMap.get("errorCode");
				boolean success = "0".equals(errorCode);
				try {
					String cusId = (String) resultMap.get("cus_id");
					String acceptorId = (String) resultMap.get("acceptor_id");
					String notaryId = (String) resultMap.get("notaryid");
					if (StringUtil.notEmpty(notaryId)) {
						contract.setNotaryId(notaryId);
					}
					this.contractFeign.saveAcceptInfo(contract, cusId, acceptorId, success);
				} catch (Exception e) {
					setErrorRec(errRec, resultMap);
					throw new UnCheckException("����������������", e);
				}
			}
		} catch (Exception e) {
			this.logger.error("������������������������: ", e);
			saveConErrRec(errRec, key, content, signed);
		}
	}

	private void saveConErrRec(ConErrRec errRec, String key, String content, String signed) {
		errRec.setErrId(SystemUtil.getUUID());
		errRec.setState("0");
		errRec.setRespKey(key);
		errRec.setRespContent(content);
		errRec.setRespSigned(signed);
		errRec.setCreateTime(DateUtil.getSystemDateTime());
		this.conErrRecFeign.saveConErrRec(errRec);
	}

	private void setErrorRec(ConErrRec errRec, Map<String, String> resultMap) {
		errRec.setErrorCode((String) resultMap.get("errorCode"));
		errRec.setErrorMsg((String) resultMap.get("errorMsg"));
		errRec.setContractId((String) resultMap.get("contract_ids"));
		errRec.setCusId((String) resultMap.get("cus_id"));
		errRec.setUserId((String) resultMap.get("acceptor_id"));
		errRec.setNotaryId((String) resultMap.get("notaryid"));
		errRec.setDocId((String) resultMap.get("docid"));
		errRec.setDocFinished((String) resultMap.get("docfinished"));
	}

	private void checkResponse(Map<String, String> resultMap) throws Exception {
		for (String key : respKeySet) {
			if (StringUtil.emptyAndNull((String) resultMap.get(key))) {
				throw new Exception(key + " is null");
			}
		}
	}

	private BatchBillStats<?> bizOperation(Set<String> billIds, String bizType, String fileIds, String contracts,
			String invoices) {
		String[] billIdArr = (String[]) billIds.toArray(new String[billIds.size()]);
		switch (bizType) {
		case "10":
			return this.billSndRevService.pass(null, null, billIdArr);
		case "11":
			return this.billXfeRevService.pass(true, null, null, billIdArr);
		case "12":
			return this.billDctRevService.pass(true, null, null, billIdArr);
		case "13":
			return this.billRcvService.contractAndreceive(billIdArr, fileIds, contracts, invoices);
		case "14":
			return this.billDctRevService.paidConfirm(null, null, billIdArr);
		}
		this.logger.error("������������: " + bizType);
		return null;
	}

	public String handleCallback(String key, String content, String signed) {
		String params = null;
		String result = null;
		Map<String, String> resultMap = null;
		try {
			try {
				result = getDecryptResult(key, content, signed);
				resultMap = (Map) JsonUtil.fromJson(result, Map.class);
			} catch (Exception e) {
				saveConErrRec(new ConErrRec(), key, content, signed);
			}
			String errorCode = (String) resultMap.get("errorCode");

			boolean success = "0".equals(errorCode);
			if (success) {
				processSuccessOption(resultMap);
			}
			StringBuilder sb = new StringBuilder("?");
			sb.append("errorCode").append("=").append((String) resultMap.get("errorCode"));
			sb.append("&").append("errorMsg").append("=").append((String) resultMap.get("errorMsg"));
			params = sb.toString();
		} catch (Exception e) {
			this.logger.error("��������������������: ", e);
			params = "?errorCode=-1&errorMsg=����������";
		}
		return params;
	}

	private void processSuccessOption(Map<String, String> resultMap) {
		String cusId = (String) resultMap.get("cus_id");
		String userId = (String) resultMap.get("acceptor_id");
		String bizType = (String) resultMap.get("biz_type");
		String fileIds = (String) resultMap.get("file_ids");
		String contracts = (String) resultMap.get("contracts");
		String invoices = (String) resultMap.get("invoices");

		setCurEntAndUser(cusId, userId);

		String contractIdsStr = (String) resultMap.get("contract_ids");
		String[] contractIds = contractIdsStr.split(",");

		Set<String> signBillIds = new HashSet();
		String signBillIdsStr = (String) resultMap.get("signed_bill_ids");
		String[] signBillIdsArr;
		if (!StringUtil.emptyAndNull(signBillIdsStr)) {
			signBillIdsArr = contractIdsStr.split(",");
			signBillIds.addAll(Arrays.asList(signBillIdsArr));
		}
		for (String contractId : contractIds) {
			Contract contract = this.contractFeign.selectByKey(contractId);
			String billId = contract.getBillId();
			if ("11".equals(bizType)) {
				CbXfe tmp = new CbXfe();
				tmp.setBillId(billId);
				tmp.setXfeState("1");
				CbXfe curXfe = (CbXfe) this.cbXfeService.selectOne(tmp);
				String prntId = curXfe.getPrntId();
				if (!billId.equals(prntId)) {
					billId = prntId;
				}
			} else if ("12".equals(bizType)) {
				CbDct tmp = new CbDct();
				tmp.setBillId(billId);
				tmp.setDctState("1");
				CbDct dct = (CbDct) this.cbDctService.selectOne(tmp);
				String prntId = dct.getPrntId();
				if (!billId.equals(prntId)) {
					billId = prntId;
				}
			}
			signBillIds.add(billId);
		}
		bizOperation(signBillIds, bizType, fileIds, contracts, invoices);
	}

	private void setCurEntAndUser(String cusId, String userId) {
		PubOrgan organ = this.pubOrganFeign.selectByKey(cusId);
		PubUser user = this.pubUserFeign.selectByKey(userId);
		AuthOrgan authOrgan = new AuthOrgan();
		authOrgan.setOrganId(organ.getOrganId());
		authOrgan.setOrganName(organ.getOrganName());
		AuthUser authUser = new AuthUser();
		authUser.setUserId(userId);
		authUser.setUserName(user.getUserName());
		authUser.setLoginName(user.getLoginName());
		authUser.setEnt(authOrgan);
		CommonDataUtil.setAuthUser(authUser);
	}

	public Map<String, String> viewDoc(String contractId) throws Exception {
		String paramStr = this.contractApiFeign.genViewDocParamStr(contractId);
		if (StringUtil.emptyAndNull(paramStr)) {
			return new HashMap();
		}
		return (Map) JsonUtil.fromJson(paramStr, Map.class);
	}

	public Map<String, String> download(String contractId) throws Exception {
		String paramStr = this.contractApiFeign.genDownloadParamStr(contractId);
		if (StringUtil.emptyAndNull(paramStr)) {
			return new HashMap();
		}
		return (Map) JsonUtil.fromJson(paramStr, Map.class);
	}

	public Result getEsignPhoneCode() {
		String userId = CommonDataUtil.getUserId();
		PubUser user = this.pubUserFeign.selectByKey(userId);
		String cusId = CommonDataUtil.getCurEntId();
		CusRec cusRec = (CusRec) this.cusRecService.selectByKey(cusId);
		if ("PERSONAL".equals(cusRec.getCusType())) {
			cusId = userId;
		}
		EsCust esCust = (EsCust) this.esCustService.selectByKey(cusId);
		if ((esCust == null) || (StringUtil.emptyAndNull(esCust.getAcctId()))) {
			throw new UnCheckMsgException("������e������������");
		}
		Result result = this.esignSignService.getMobileCode(esCust.getAcctId(), user.getPhoneNo());
		if (result.getErrCode() != 0) {
			throw new UnCheckMsgException("��������������������" + result.getMsg());
		}
		return result;
	}

	public RetMsg sendCfcaPaperlessSignPhoneCode() {
		String userId = CommonDataUtil.getUserId();
		String phoneCode = String.valueOf(RandomUtil.getRandomInt(6));
		PubUser user = this.pubUserFeign.selectByKey(userId);
		PaperlessSignKeyWord keyword = new PaperlessSignKeyWord();
		keyword.setValidPeriod(String.valueOf(CfcaConfiguration.getCfcaSmsValidPeriod()));
		keyword.setUserId(user.getUserId());
		keyword.setPhoneCode(phoneCode);
		String keywordJson = null;
		try {
			keywordJson = JsonUtil.toJson(keyword);
		} catch (Exception e) {
			this.logger.error("json��������", e);
		}
		String keywordClassName = keyword.getClass().getName();
		SMSResponse response = this.pubMessageFeign.sendMessageToPhone(user.getPhoneNo(), "", "MT08011", keywordJson,
				keywordClassName);
		RetMsg msg;
		if (response.isSuccess()) {
			CfcaSmsLog cfcaSmsLog = new CfcaSmsLog();
			cfcaSmsLog.setSmsId(SystemUtil.getUUID());
			cfcaSmsLog.setPhoneNo(user.getPhoneNo());
			cfcaSmsLog.setPhoneCode(phoneCode);
			cfcaSmsLog.setUserId(userId);
			cfcaSmsLog.setSendTime(response.getSendTime());
			cfcaSmsLog.setSmsGateway(this.smsGateway);
			cfcaSmsLog.setContent(response.getContent());
			this.cfcaSmsLogService.save(cfcaSmsLog);

			msg = new RetMsg("success", false, "��������������");
			if (!SystemUtil.SystemMode.prod.equals(SystemUtil.getSystemMode())) {
				msg.setBean(phoneCode);
			}
		} else {
			msg = new RetMsg("error", true, "����������������" + response.getErrMsg());
		}
		return msg;
	}

	private String getDecryptResult(String key, String content, String signed) throws Exception {
		return this.contractApiFeign.decryptContent(key, content, signed);
	}
}
